#!/usr/bin/perl
use FindBin;
use lib "$FindBin::Bin/lib";
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../pllib/lib/perl5";

use strict;
use POSIX;
use Encode;
use Net::Netmask;

use AutoExecUtils;

sub getWindowsNicInfo {

    my $codepage;
    eval {
        q{
            use Win32::API;
            if ( Win32::API->Import( 'kernel32', 'int GetACP()' ) ) {
                $codepage = 'cp'.GetACP();
            }
        }
    };

    # Description                              MACAddress
    # Intel(R) PRO/1000 MT Network Connection  00:0C:29:28:7D:49
    my $macsMap      = {};
    my @nicInfoLines = `wmic nicconfig where "IPEnabled = True" get description,macaddress`;
    if ( $? != 0 ) {
        die("ERROR: Execute wmic nicconfig failed.\n");
    }
    my $nicInfoLinesCount = scalar(@nicInfoLines);
    for ( my $i = 1 ; $i < $nicInfoLinesCount ; $i++ ) {
        my $line = $nicInfoLines[$i];
        $line = Encode::encode( "utf-8", Encode::decode( $codepage, $line ) );
        $line =~ s/^\s*|\s*$//g;

        my @nicInfoSegs = split( /\s+/, $line );
        my $nicMac      = lc( pop(@nicInfoSegs) );
        my $nicName     = substr( $line, 0, length($line) - 17 );
        if ( length($nicMac) == 17 and $nicName ne '' ) {
            $nicName =~ s/^\s*|\s*$//g;
            if ( not defined( $macsMap->{$nicMac} ) ) {
                my $nicInfo = {};
                $nicInfo->{name}    = $nicName;
                $nicInfo->{mac}     = $nicMac;
                $macsMap->{$nicMac} = $nicInfo;
            }
        }
    }

    return $macsMap;
}

sub getWindowsIpAddrs {
    my ($macsMap) = @_;

    # IPAddress         IPSubnet                 MACAddress
    # {"192.168.0.35"}  {"255.255.255.0"}        00:0C:29:5E:C8:C2
    # IPAddress                                     IPSubnet                 MACAddress
    # {"10.0.249.114", "fe80::1aa:f8e7:a15d:888d"}  {"255.255.255.0", "64"}  00:0C:29:5E:C8:C2
    my $ipMap       = {};
    my @ipInfoLines = `wmic nicconfig where "IPEnabled = True" get ipaddress,ipsubnet,macaddress'`;
    if ( $? != 0 ) {
        die("ERROR: Execute wmic nicconfig failed.\n");
    }
    foreach my $line (@ipInfoLines) {
        if ( $line =~ /\{(.*?)\}\s+\{(.*?)\}\s+([A-Fa-f0-9:]+)/ ) {
            my @ips      = split( /\s*,\s*/, $1 );
            my @netmasks = split( /\s*,\s*/, $2 );
            my $mac      = lc($3);

            my $ipCount = scalar(@ips);
            for ( my $i = 0 ; $i < $ipCount ; $i++ ) {
                my $ip = lc( $ips[$i] );
                $ip =~ s/"//g;
                my $netmask = $netmasks[$i];
                $netmask =~ s/"//g;

                if ( $ip !~ /^127\./ and $ip ne '::1' ) {
                    my $ipInfo = $ipMap->{$ip};
                    if ( not defined($ipInfo) ) {
                        $ipInfo = {};
                        $ipMap->{$ip} = $ipInfo;
                    }
                    my $ipType = 'IPV6';
                    if ( $ip =~ /^\d+\.\d+\.\d+\.\d+$/ ) {
                        $ipType = 'IPV4';
                    }
                    $ipInfo->{ip}      = $ip;
                    $ipInfo->{type}    = $ipType;
                    $ipInfo->{nic}     = $macsMap->{$mac};
                    $ipInfo->{mac}     = $mac;
                    $ipInfo->{netmask} = $netmask;
                }
            }
        }
    }
    return $ipMap;
}

sub main {
    my @uname    = uname();
    my $osType   = $uname[0];
    my $ipString = "";

    my $hasError = 0;

    my @ifconfigLines = `ifconfig -a`;
    if ( $? != 0 ) {
        print("WANR: Execute ifconfig failed, try to use ip addr to get nic information.\n");
        @ifconfigLines = `ip addr`;
    }
    if ( $? != 0 ) {
        $hasError = 1;
        print("ERROR: Execute ip addr failed.\n");
    }

    my $nicMap = {};
    my $ipMap  = {};

    if ( $osType =~ /Windows/i ) {
        my $macsMap = getWindowsNicInfo();
        $ipMap = getWindowsIpAddrs($macsMap);

        while ( my ( $mac, $nicInfo ) = each(%$macsMap) ) {
            $nicMap->{ $nicInfo->{name} } = $mac;
        }
    }
    else {

        my $nicName;
        foreach my $line (@ifconfigLines) {
            if ( $line =~ /^(\w+)[:\s]/ or $line =~ /^\d+:\s+(\w+):/ ) {
                $nicName = $1;
            }
            if ( $line =~ /ether\s+([0-9a-f:]+)/i or $line =~ /HWaddr\s+([0-9a-f:]+)/i ) {
                my $mac = lc($1);
                $nicMap->{$nicName} = $mac;
            }
        }

        $nicName = undef;
        foreach my $line (@ifconfigLines) {
            if ( $line =~ /^(\w+)[:\s]/ or $line =~ /^\d+:\s+(\w+):/ ) {
                $nicName = $1;
            }
            elsif ( $line =~ /inet\s+([\d\.]+)\s+netmask\s+([\d\.]+)/i or $line =~ /inet addr:\s*([\d\.]+)\s+.*?\s+Mask:\s*([\d\.]+)/i ) {
                my $ip      = $1;
                my $netmask = $2;
                if ( $ip eq '127.0.0.1' or $ip eq '::1' ) {
                    next;
                }

                my $ipInfo = $ipMap->{$ip};
                if ( not defined($ipInfo) ) {
                    $ipInfo = {};
                    $ipMap->{$ip} = $ipInfo;
                }
                $ipInfo->{ip}   = $ip;
                $ipInfo->{type} = 'IPV4';
                $ipInfo->{nic}  = $nicName;
                $ipInfo->{mac}  = $nicMap->{$nicName};
                my $netBlock = Net::Netmask->safe_new("$ip:$netmask");
                $ipInfo->{netmask} = $netBlock->bits();
            }
            elsif ( $line =~ /inet6\s+([0-9a-f:]+)\s+prefixlen\s+([\d]+)/i or $line =~ /inet6 addr:\s*([0-9a-f:]+)\/([\d]+)/i ) {
                my $ip      = lc($1);
                my $netmask = $2;
                if ( $ip eq '127.0.0.1' or $ip eq '::1' ) {
                    next;
                }

                my $ipInfo = $ipMap->{$ip};
                if ( not defined($ipInfo) ) {
                    $ipInfo = {};
                    $ipMap->{$ip} = $ipInfo;
                }
                $ipInfo->{ip}      = $ip;
                $ipInfo->{type}    = 'IPV6';
                $ipInfo->{nic}     = $nicName;
                $ipInfo->{mac}     = $nicMap->{$nicName};
                $ipInfo->{netmask} = $netmask;
            }
        }
    }

    my $nicsTxt = '';
    while ( my ( $name, $mac ) = each(%$nicMap) ) {
        $nicsTxt = $nicsTxt . "$mac $name\n";
    }

    my @allIpInfo = values(%$ipMap);
    my $out       = {};
    $out->{allIpInfo} = \@allIpInfo;
    $out->{allNics}   = $nicsTxt;

    AutoExecUtils::saveOutput($out);

    return $hasError;
}

exit main();
